package com.siyoumi.app.modules.app_ess.service;

import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.siyoumi.app.entity.*;
import com.siyoumi.app.modules.app_ess.vo.*;
import com.siyoumi.app.modules.fun.service.SvcFun;
import com.siyoumi.app.modules.fun.vo.VaFunAdd;
import com.siyoumi.app.service.*;
import com.siyoumi.component.XApp;
import com.siyoumi.component.XBean;
import com.siyoumi.component.XSpringContext;
import com.siyoumi.component.http.InputData;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.mybatispuls.JoinWrapperPlus;
import com.siyoumi.service.IWebService;
import com.siyoumi.util.XDate;
import com.siyoumi.util.XJson;
import com.siyoumi.util.XReturn;
import com.siyoumi.util.XStr;
import com.siyoumi.validator.XValidator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

//能力评价
@Slf4j
@Service
public class SvcEssTest
        implements IWebService {
    static public SvcEssTest getBean() {
        return XSpringContext.getBean(SvcEssTest.class);
    }

    static public EssTestService getApp() {
        return EssTestService.getBean();
    }


    public Map<String, Object> toMap(EssTest entityTest) {
        Map<String, Object> mapTest = XBean.toMap(entityTest, new String[]{
                "etest_id",
                "etest_title",
                "etest_test_minute",
                "etest_test_not_submit",
                "etest_test_end_remind",
                "etest_fun_total",
                "etest_question_total",
                "etest_submit_total",
                "etest_test_total",
                "etest_date_begin",
                "etest_date_end",
                "etest_score_show",
        });
        return mapTest;
    }

    /**
     * 任务状态
     *
     * @param entity
     */
    public XReturn getState(EssTest entity) {
        if (entity.getEtest_state() == 0) {
            return XReturn.getR(20030, "未发布");
        }

        if (XDate.now().isBefore(entity.getEtest_date_begin())) {
            return XReturn.getR(20040, "未开始");
        }

        if (XDate.now().isAfter(entity.getEtest_date_end())) {
            return XReturn.getR(20050, "已结束");
        }

        return EnumSys.OK.getR("进行中");
    }

    /**
     * 任务状态
     *
     * @param entity
     */
    public XReturn getResultSubmitState(EssTestResult entity) {
        if (entity.getEtres_submit() == 1) {
            return EnumSys.OK.getR("已提交");
        }
        if (entity.getEtres_submit() == 10) {
            return EnumSys.OK.getR("进行中");
        }

        return EnumSys.OK.getR("未进入");
    }

    public JoinWrapperPlus<EssTest> listQuery() {
        return listQuery(InputData.getIns());
    }

    /**
     * select
     *
     * @return query
     */
    public JoinWrapperPlus<EssTest> listQuery(InputData inputData) {
        String id = inputData.input("id");
        String title = inputData.input("title");
        String date = inputData.input("date");
        String state = inputData.input("state");

        JoinWrapperPlus<EssTest> query = getApp().join();
        query.eq("etest_x_id", XHttpContext.getX()).eq("etest_del", 0);
        query.orderByDesc("etest_id");

        if (XStr.hasAnyText(id)) { //ID
            query.like("etest_id", id);
        } else {
            if (XStr.hasAnyText(title)) { //名称
                query.like("etest_title", title);
            }
            if (XStr.hasAnyText(date)) { //日期
                LocalDateTime d = XDate.parse(date);
                query.gt("etest_date_begin", d).lt("etest_date_end", d);
            }
            if (XStr.hasAnyText(state)) { //状态
                switch (state) {
                    case "0": //未发布
                        query.eq("etest_state", 0);
                        break;
                    case "1": //未开始
                        query.eq("etest_state", 1).gt("etest_date_begin", XDate.now());
                        break;
                    case "2": //进行中
                        query.eq("etest_state", 1).lt("etest_date_begin", XDate.now()).gt("etest_date_end", XDate.now());
                        break;
                    case "3": //已结束
                        query.eq("etest_state", 1).lt("etest_date_end", XDate.now());
                        break;
                }
            }
        }


        return query;
    }

    /**
     * 删除学生
     *
     * @param testId
     */
    public XReturn delStudent(String testId) {
        JoinWrapperPlus<EssTestStudent> query = listStudentQuery(testId);
        EssTestStudentService.getBean().remove(query);

        return EnumSys.OK.getR();
    }

    public JoinWrapperPlus<EssTestStudent> listStudentQuery(InputData inputData) {
        String testId = inputData.input("test_id");

        JoinWrapperPlus<EssTestStudent> query = EssTestStudentService.getBean().join();
        query.eq("etcla_x_id", XHttpContext.getX());
        if (XStr.hasAnyText(testId)) { //评测
            query.eq("etcla_test_id", testId);
        }

        return query;
    }

    public JoinWrapperPlus<EssTestStudent> listStudentQuery(String testId) {
        JoinWrapperPlus<EssTestStudent> query = listStudentQuery(InputData.getIns());
        query.eq("etcla_test_id", testId);

        return query;
    }

    public JoinWrapperPlus<EssTestQuestion> listQuestionQuery(InputData inputData) {
        String testId = inputData.input("test_id");

        JoinWrapperPlus<EssTestQuestion> query = EssTestQuestionService.getBean().join();
        query.eq("etques_x_id", XHttpContext.getX());
        query.orderByAsc("etques_order").orderByDesc("etques_id");
        if (XStr.hasAnyText(testId)) { //评测
            query.eq("etques_test_id", testId);
        }

        return query;
    }

    public JoinWrapperPlus<EssTestQuestion> listQuestionQuery(String testId) {
        JoinWrapperPlus<EssTestQuestion> query = listQuestionQuery(InputData.getIns());
        query.eq("etques_test_id", testId);
        return query;
    }

    public JoinWrapperPlus<EssTestResult> listResultQuery(InputData inputData) {
        String testId = inputData.input("test_id");
        String submit = inputData.input("submit");
        String uid = inputData.input("uid");

        JoinWrapperPlus<EssTestResult> query = EssTestResultService.getBean().join();
        query.eq("etres_x_id", XHttpContext.getX());
        if (XStr.hasAnyText(uid)) { //学生uid
            query.eq("etres_uid", uid);
        }
        if (XStr.hasAnyText(testId)) { //评测
            query.eq("etres_test_id", testId);
        }
        if (XStr.hasAnyText(submit)) { //提交状态
            if ("1".equals(submit)) {
                query.in("etres_submit", 1);
            } else { //缺考
                query.in("etres_submit", 0, 10);
            }
        } else {
            query.in("etres_submit", 0, 1, 10);
        }

        return query;
    }

    public JoinWrapperPlus<EssTestResult> listResultQuery(String testId) {
        InputData inputData = InputData.getIns();
        inputData.put("test_id", testId);
        return listResultQuery(inputData);
    }

    public JoinWrapperPlus<EssTestResultItem> listResultItemQuery(InputData inputData) {
        String testId = inputData.input("test_id");
        String questionId = inputData.input("question_id");

        JoinWrapperPlus<EssTestResultItem> query = EssTestResultItemService.getBean().join();
        query.eq("etri_x_id", XHttpContext.getX());
        if (XStr.hasAnyText(testId)) { //评测
            query.eq("etri_test_id", testId);
        }
        if (XStr.hasAnyText(questionId)) { //题目ID
            query.eq("etri_question_id", questionId);
        }

        return query;
    }

    public JoinWrapperPlus<EssTestResultItem> listResultItemQuery() {
        return listResultItemQuery(InputData.getIns());
    }

    public XReturn valid(EssTest entityTest) {
        if (entityTest == null) {
            return EnumSys.ERR_VAL.getR("评测ID异常");
        }
        if (entityTest.getEtest_del() != 0) {
            return XReturn.getR(20117, "评测不存在");
        }
        return EnumSys.OK.getR();
    }

    /**
     * 能否编辑
     *
     * @param entityTest
     */
    public XReturn editCan(EssTest entityTest) {
        XReturn r = valid(entityTest);
        if (r.err()) {
            return r;
        }
        if (entityTest.getEtest_state() == 1) {
            return XReturn.getR(20127, "评测已发布");
        }
        if (!entityTest.getEtest_uid().equals(getUid())) {
            return XReturn.getR(20137, "帐号权限不足");
        }

        return EnumSys.OK.getR();
    }

    /**
     * 添加测评
     */
    public XReturn add(InputData inputData, VoEssTestAdd vo) {
        List<String> ignoreField = new ArrayList<>();
        if (inputData.isAdminEdit()) {
            EssTest entityTest = getApp().loadEntity(inputData.getID());
            if (entityTest.getEtest_state() == 1) {
                return XReturn.getR(20200, "评测已发布");
            }

            ignoreField.add("etest_uid");
        }

        return XApp.getTransaction().execute(status -> {
            XReturn r = EssTestService.getBean().saveEntity(inputData, vo, true, ignoreField);
            return r;
        });
    }

    /**
     * 添加学生
     */
    @Transactional(rollbackFor = Exception.class)
    public XReturn addStudent(VoEssTestAddStudent vo) {
        EssTest entityTest = getApp().getEntity(vo.getTest_id());
        XValidator.err(editCan(entityTest));

        //先删除已有学生
        delStudent(entityTest.getKey());
        //重新添加选中学生
        List<EssTestStudent> list = new ArrayList<>();
        for (String uid : vo.getStudent_uids()) {
            EssTestStudent entity = new EssTestStudent();
            entity.setEtcla_uid(uid);
            entity.setEtcla_test_id(entityTest.getKey());
            entity.setAutoID();
            entity.setEtcla_x_id(XHttpContext.getX());

            list.add(entity);
        }
        EssTestStudentService.getBean().saveBatch(list);

        //更新人数
        EssTest entityTestUpdate = new EssTest();
        entityTestUpdate.setEtest_test_total((long) vo.getStudent_uids().size());
        getApp().saveOrUpdatePassEqualField(entityTest, entityTestUpdate);

        return EnumSys.OK.getR();
    }

    /**
     * 添加试题
     */
    @Transactional(rollbackFor = Exception.class)
    public XReturn batchAddQuestion(VoEssTestBatchAddQuestion vo) {
        EssTest entityTest = getApp().getEntity(vo.getTest_id());
        XValidator.err(editCan(entityTest));
        if (vo.getType() == 0) {
            if (entityTest.getEtest_question_total() > 0) {
                return EnumSys.ARR_SIZE_0.getR("试卷已生成，无法添加试题");
            }
        }

        Integer order = 0;
        List<EssTestQuestion> list = new ArrayList<>();
        if (vo.getType() == 0) {
            //随机选题
            if (vo.getList_auto() == null || vo.getList_auto().isEmpty()) {
                return EnumSys.ARR_SIZE_0.getR("请选择场景");
            }

            for (VoEssTestBatchAddQuestionAuto item : vo.getList_auto()) {
                XValidator.isNullOrEmpty(item.getModule_id(), "miss module_id");
                XValidator.isNull(item.getFun(), "miss fun");
                XValidator.isNull(item.getType(), "miss type");
                XValidator.isNull(item.getQuestion_count(), "miss question_count");

                if (item.getQuestion_count() <= 0) {
                    EssModule entityModule = SvcEssModule.getApp().getEntity(item.getModule_id());
                    return EnumSys.ERR_VAL.getR(entityModule.getEmod_name() + "：请选择题目数量");
                }
            }
            //添加题目
            for (VoEssTestBatchAddQuestionAuto item : vo.getList_auto()) {
                List<String> questionIds = SvcEssQuestion.getBean().getIds(item.getModule_id(), item.getType(), item.getQuestion_count()); //随机选题要想想
                for (String questionId : questionIds) {
                    EssTestQuestion entity = new EssTestQuestion();
                    entity.setEtques_x_id(XHttpContext.getX());
                    entity.setEtques_test_id(entityTest.getKey());
                    entity.setEtques_module_id(item.getModule_id());
                    entity.setEtques_question_id(questionId);
                    entity.setEtques_fun(item.getFun().longValue());
                    entity.setAutoID();
                    entity.setEtques_order(order);
                    list.add(entity);

                    order++;
                }
            }
        } else {
            if (vo.getList_hand() == null || vo.getList_hand().isEmpty()) {
                return EnumSys.ARR_SIZE_0.getR("请选择题目");
            }

            List<String> questionIds = vo.getList_hand().stream().map(item -> item.getQuestion_id()).collect(Collectors.toList());

            //手动选题
            JoinWrapperPlus<EssQuestion> query = SvcEssQuestion.getBean().listQuery(entityTest.getKey());
            query.in(EssQuestion.tableKey(), questionIds);
            query.select("etqu_id", "etqu_module_id");
            List<Map<String, Object>> listQuestion = SvcEssQuestion.getApp().getMaps(query);
            if (listQuestion.isEmpty()) {
                return EnumSys.ARR_SIZE_0.getR("题目ID异常");
            }

            for (Map<String, Object> item : listQuestion) {
                String questionId = (String) item.get("etqu_id");
                String moduleId = (String) item.get("etqu_module_id");
                //题目配置信息
                VoEssTestBatchAddQuestionHand itemQuestion = vo.getList_hand().stream().filter(i -> i.getQuestion_id().equals(questionId)).findFirst().orElse(null);

                EssTestQuestion entity = new EssTestQuestion();
                entity.setEtques_x_id(XHttpContext.getX());
                entity.setEtques_test_id(entityTest.getKey());
                entity.setEtques_module_id(moduleId);
                entity.setEtques_question_id(questionId);
                entity.setEtques_fun(itemQuestion.getFun().longValue());
                entity.setAutoID();
                entity.setEtques_order(order);
                list.add(entity);

                order++;
            }
        }
        EssTestQuestionService.getBean().saveBatch(list);
        //更新积分总数，题目总数
        updateTotal(entityTest.getKey());

        return EnumSys.OK.getR();
    }

    /**
     * 清空题目
     */
    public XReturn delQuestion(VoEssTestQuestionDel vo) {
        EssTest entityTest = getApp().getEntity(vo.getTest_id());
        XValidator.err(editCan(entityTest));

        JoinWrapperPlus<EssTestQuestion> query = EssTestQuestionService.getBean().join();
        query.eq("etques_test_id", vo.getTest_id());
        if (XStr.hasAnyText(vo.getQuestion_id())) { //删除指定题目
            query.eq("etques_id", vo.getQuestion_id());
        }
        EssTestQuestionService.getBean().remove(query);

        updateTotal(vo.getTest_id());

        return EnumSys.OK.getR();
    }

    /**
     * 更新积分总数，题目总数
     *
     * @param testId
     */
    protected void updateTotal(String testId) {
        JoinWrapperPlus<EssTestQuestion> query = EssTestQuestionService.getBean().join();
        query.eq("etques_test_id", testId);
        query.select("COUNT(*) count", "IFNULL(SUM(etques_fun),0) fun");
        Map<String, Object> mapData = EssTestQuestionService.getBean().firstMap(query);
        BigDecimal fun = (BigDecimal) mapData.get("fun");

        EssTest entityTestUpdate = new EssTest();
        entityTestUpdate.setEtest_id(testId);
        entityTestUpdate.setEtest_question_total((Long) mapData.get("count"));
        entityTestUpdate.setEtest_fun_total(fun.longValue());
        getApp().updateById(entityTestUpdate);
    }

    /**
     * 或者添加编辑题目
     */
    public XReturn editQuestion(InputData inputData, VoEssTestQuestion vo) {
        EssTest entityTest = getApp().getEntity(vo.getEtques_test_id());
        XValidator.err(editCan(entityTest));
        {
            EssQuestion entityQuestion = SvcEssQuestion.getApp().getEntity(vo.getEtques_question_id());
            XValidator.isNull(entityQuestion, "题目ID异常");
            vo.setEtques_module_id(entityQuestion.getEtqu_module_id());
        }
        {
            JoinWrapperPlus<EssTestQuestion> query = listQuestionQuery(entityTest.getKey());
            query.eq("etques_question_id", vo.getEtques_question_id());
            if (inputData.isAdminEdit()) {
                query.ne(EssTestQuestion.tableKey(), inputData.getID());
            }
            EssTestQuestion entityQuestion = EssTestQuestionService.getBean().first(query);
            if (entityQuestion != null) {
                return EnumSys.ERR_VAL.getR("题目已添加");
            }
        }


        List<String> ignoreField = new ArrayList<>();
        if (inputData.isAdminEdit()) {
            ignoreField.add("etques_module_id");
            ignoreField.add("etques_test_id");
            //ignoreField.add("etques_question_id");
        }

        return XApp.getTransaction().execute(status -> {
            XReturn r = EssTestQuestionService.getBean().saveEntity(inputData, vo, true, ignoreField);
            if (r.ok()) {
                EssTestQuestion entity = r.getData("entity");

                updateTotal(entity.getEtques_test_id());
            }

            return r;
        });
    }


    /**
     * 发布，撤消发布
     */
    @Transactional(rollbackFor = Exception.class)
    public XReturn audit(VoEssTestAudit vo) {
        EssTest entityTest = getApp().getEntity(vo.getTest_id());
        XReturn r = valid(entityTest);
        if (r.err()) {
            return r;
        }
        if (!entityTest.getEtest_uid().equals(getUid())) {
            return XReturn.getR(20137, "帐号权限不足");
        }
        if (entityTest.getEtest_state().equals(vo.getState())) {
            return XReturn.getR(0, "操作成功");
        }
        if (vo.getState() == 1) {
            if (entityTest.getEtest_test_total() <= 0) {
                return XReturn.getR(20147, "学生数量为0，请添加学生");
            }
            if (entityTest.getEtest_question_total() <= 0) {
                return XReturn.getR(20157, "题目数量为0，请添加题目");
            }
            if (XDate.now().isAfter(entityTest.getEtest_date_end())) {
                return XReturn.getR(20050, "测评已结束，请重新设置时间");
            }
        }

        if (vo.getState() == 1) {
            //发布，发考卷给学生
            JoinWrapperPlus<EssTestStudent> query = listStudentQuery(entityTest.getKey());
            query.join(EssClassUser.table(), "ecu_uid", "etcla_uid");
            query.select("etcla_uid", "ecu_class_id");
            List<Map<String, Object>> listStudent = EssTestStudentService.getBean().getMaps(query);
            List<EssTestResult> list = new ArrayList<>();
            for (Map<String, Object> item : listStudent) {
                String uid = (String) item.get("etcla_uid");
                String classId = (String) item.get("ecu_class_id");
                EssTestResult entity = new EssTestResult();
                entity.setEtres_x_id(XHttpContext.getX());
                entity.setEtres_test_id(entityTest.getKey());
                entity.setEtres_class_id(classId);
                entity.setEtres_uid(uid);
                entity.setAutoID();
                list.add(entity);
            }
            EssTestResultService.getBean().saveBatch(list);
        } else {
            //撤消发布，删除试卷
            {
                JoinWrapperPlus<EssTestResult> query = listResultQuery(entityTest.getKey());
                EssTestResultService.getBean().remove(query);
            }
            //删除试卷明细
            {
                JoinWrapperPlus<EssTestResultItem> query = EssTestResultItemService.getBean().join();
                query.eq("etri_test_id", entityTest.getKey());
                EssTestResultItemService.getBean().remove(query);
            }
        }

        //更新状态
        EssTest entityTestUpdate = new EssTest();
        entityTestUpdate.setEtest_state(vo.getState());
        entityTestUpdate.setEtest_state_date(LocalDateTime.now());
        getApp().saveOrUpdatePassEqualField(entityTest, entityTestUpdate);

        return EnumSys.OK.getR();
    }

    /**
     * 复制
     */
    @Transactional(rollbackFor = Exception.class)
    public XReturn copy(VoEssTestCopy vo) {
        EssTest entityTestSrc = getApp().getEntity(vo.getTest_id());
        XReturn r = valid(entityTestSrc);
        if (r.err()) {
            return r;
        }

        for (String teacherUid : vo.getTeacher_uids()) {
            //评测
            EssTest entityTestNew = new EssTest();
            XBean.copyProperties(entityTestSrc, entityTestNew);
            entityTestNew.setAutoID();
            entityTestNew.setEtest_create_date(null);
            entityTestNew.setEtest_update_date(null);
            entityTestNew.setEtest_submit_fun_total(null);
            entityTestNew.setEtest_submit_total(null);
            entityTestNew.setEtest_send_fun(null);
            entityTestNew.setEtest_send_fun_date(null);
            entityTestNew.setEtest_uid(teacherUid);
            entityTestNew.setEtest_state(0);
            entityTestNew.setEtest_state_date(XDate.date2000());
            entityTestNew.setEtest_title(vo.getTest_title());
            getApp().save(entityTestNew);

            //学生
            {
                JoinWrapperPlus<EssTestStudent> query = listStudentQuery(entityTestSrc.getKey());
                List<EssTestStudent> listSrc = EssTestStudentService.getBean().get(query);
                List<EssTestStudent> list = new ArrayList<>();
                for (EssTestStudent entitySrc : listSrc) {
                    EssTestStudent entity = new EssTestStudent();
                    XBean.copyProperties(entitySrc, entity);
                    entity.setEtcla_create_date(null);
                    entity.setEtcla_update_date(null);
                    entity.setEtcla_test_id(entityTestNew.getKey());
                    entity.setAutoID();

                    list.add(entity);
                }
                EssTestStudentService.getBean().saveBatch(list);
            }

            //题目
            {
                JoinWrapperPlus<EssTestQuestion> query = listQuestionQuery(entityTestSrc.getKey());
                List<EssTestQuestion> listSrc = EssTestQuestionService.getBean().get(query);
                List<EssTestQuestion> list = new ArrayList<>();
                for (EssTestQuestion entitySrc : listSrc) {
                    EssTestQuestion entity = new EssTestQuestion();
                    XBean.copyProperties(entitySrc, entity);
                    entity.setEtques_create_date(null);
                    entity.setEtques_update_date(null);
                    entity.setEtques_test_id(entityTestNew.getKey());
                    entity.setEtques_answer_bingo_total(null);
                    entity.setAutoID();

                    list.add(entity);
                }
                EssTestQuestionService.getBean().saveBatch(list);
            }
        }
        return EnumSys.OK.getR();
    }


    /**
     * 删除
     */
    @SneakyThrows
    @Transactional(propagation = Propagation.MANDATORY)
    public XReturn delete(List<String> ids) {
        XReturn r = XReturn.getR(0);

        getApp().delete(ids);

        return r;
    }

    /**
     * 添加时长
     *
     * @param vo
     */
    public XReturn addTime(VoEssTestAddTime vo) {
        EssTest entityTest = getApp().getEntity(vo.getTest_id());
        XReturn r = valid(entityTest);
        XValidator.err(r);

        if (!entityTest.getEtest_uid().equals(getUid())) {
            return XReturn.getR(20137, "帐号权限不足");
        }

        if (vo.getTest_minute() <= 0 && vo.getAdd_date_end() <= 0) {
            return EnumSys.OK.getR("无需修改");
        }

        EssTest entityUpdate = new EssTest();
        entityUpdate.setEtest_id(entityTest.getKey());
        if (vo.getTest_minute() > 0) { //修改考试时长
            entityUpdate.setEtest_test_minute(vo.getTest_minute());
        }
        if (vo.getAdd_date_end() > 0) { //添加结束时间
            entityUpdate.setEtest_date_end(entityTest.getEtest_date_end().plusHours(vo.getAdd_date_end()));
        }
        getApp().saveOrUpdatePassEqualField(entityTest, entityUpdate);

        return EnumSys.OK.getR();
    }

    /**
     * 老师公布成绩
     */
    @Transactional(rollbackFor = Exception.class)
    public XReturn showResult(VoEssTestShowResult vo) {
        EssTest entityTest = getApp().getEntity(vo.getTest_id());
        XReturn r = valid(entityTest);
        XValidator.err(r);
        if (entityTest.getEtest_state() == 0) {
            return XReturn.getR(20040, "测评未发布");
        }
        if (!XDate.now().isAfter(entityTest.getEtest_date_end())) {
            return XReturn.getR(20050, "测评未结束");
        }
        if (!entityTest.getEtest_uid().equals(getUid())) {
            return XReturn.getR(20137, "帐号权限不足");
        }
        if (entityTest.getEtest_score_show() == 1) {
            return XReturn.getR(20147, "设置答题结束公布成绩，无需手动");
        }

        //成功公开成绩状态
        EssTest entityUpdate = new EssTest();
        entityUpdate.setEtest_id(entityTest.getKey());
        entityUpdate.setEtest_send_fun(1);
        entityUpdate.setEtest_send_fun_date(XDate.now());
        getApp().saveOrUpdatePassEqualField(entityTest, entityUpdate);
        //发积分
        sendFun(entityTest, null);

        return EnumSys.OK.getR();
    }

    /**
     * 公布成绩发分
     *
     * @param entityTest
     * @param resultId
     */
    private void sendFun(EssTest entityTest, String resultId) {
        UpdateChainWrapper<EssTestResult> update = EssTestResultService.getBean().update()
                .set("etres_send_fun", 1)
                .set("etres_end", 1)
                .eq("etres_test_id", entityTest.getKey());
        if (XStr.hasAnyText(resultId)) { //某个成绩
            update.eq("etres_id", resultId);
        }
        update.update();

        //发放积分
        JoinWrapperPlus<EssTestResult> query = listResultQuery(entityTest.getKey());
        //query.gt("etres_test_fun", 0);
        if (XStr.hasAnyText(resultId)) { //某个成绩
            query.eq("etres_id", resultId);
        }
        List<EssTestResult> listResult = EssTestResultService.getBean().get(query);
        for (EssTestResult entityResult : listResult) {
            if (entityResult.getEtres_test_fun() > 0) {
                VaFunAdd vaFunAdd = VaFunAdd.of(entityResult.getKey()
                        , entityResult.getEtres_uid()
                        , entityTest.getKey()
                        , "app_ess"
                        , entityResult.getEtres_test_fun().intValue()
                        , entityTest.getEtest_title() + "得分");
                vaFunAdd.setUpdate_fun(true);
                SvcFun.getBean().add(vaFunAdd);
            }

            SvcEssUser.getBean().updateTotal(entityResult.getEtres_uid(), null, "test0", entityResult.getEtres_test_fun().intValue());
        }
    }

    /**
     * 学生开始考试
     */
    public XReturn startTest(VoEssTestStartTest vo) {
        EssTestResult entityResult = EssTestResultService.getBean().getEntity(vo.getResult_id());
        XValidator.isNull(entityResult, "试卷ID异常");
        //
        EssTest entityTest = getApp().getEntity(entityResult.getEtres_test_id());
        XValidator.err(valid(entityTest));
        XValidator.err(getState(entityTest));

        if (!entityResult.getEtres_uid().equals(getUid())) {
            return XReturn.getR(20629, "用户异常");
        }
        if (entityResult.getEtres_submit() != 0) {
            return XReturn.getR(20639, "已开始考试");
        }
        if (entityResult.getEtres_end() == 1) {
            return XReturn.getR(20649, "已结束");
        }

        return XApp.getTransaction().execute(status -> {
            EssTestResult entityUpdate = new EssTestResult();
            entityUpdate.setEtres_id(entityResult.getEtres_id());
            entityUpdate.setEtres_submit(10); //进行中
            entityUpdate.setEtres_submit_date(XDate.now());
            entityUpdate.setEtres_submit_date_end(XDate.now().plusMinutes(entityTest.getEtest_test_minute())); //考虑结束时间
            EssTestResultService.getBean().saveOrUpdatePassEqualField(entityResult, entityUpdate);

            List<EssTestQuestion> listQuestion = EssTestQuestionService.getBean().get(listQuestionQuery(entityTest.getKey()));
            if (entityTest.getEtest_random() == 1) {
                //题目要打乱顺序
                Collections.shuffle(listQuestion);
            }
            //生成题目
            List<EssTestResultItem> listResultItem = new ArrayList<>();
            for (EssTestQuestion entityQuesion : listQuestion) {
                EssTestResultItem entityItem = new EssTestResultItem();
                entityItem.setEtri_result_id(entityResult.getKey());
                entityItem.setEtri_test_id(entityResult.getEtres_test_id());
                entityItem.setEtri_etques_id(entityQuesion.getKey());
                entityItem.setEtri_question_id(entityQuesion.getEtques_question_id());
                entityItem.setEtri_test_fun(entityQuesion.getEtques_fun().longValue());
                entityItem.setEtri_x_id(XHttpContext.getX());
                entityItem.setEtri_uid(entityResult.getEtres_uid());
                entityItem.setEtri_class_id(entityResult.getEtres_class_id());
                entityItem.setAutoID();

                listResultItem.add(entityItem);
            }
            EssTestResultItemService.getBean().saveBatch(listResultItem);

            return EnumSys.OK.getR();
        });
    }

    /**
     * 学生提交答案
     */
    public XReturn answer(VoEssTestAnswer vo) {
        EssTestResult entityResult = EssTestResultService.getBean().getEntity(vo.getResult_id());
        XValidator.isNull(entityResult, "试卷ID异常");
        if (entityResult.getEtres_end() == 1) {
            return XReturn.getR(20666, "考试已结束");
        }
        EssTest entityTest = getApp().getEntity(entityResult.getEtres_test_id());
        XReturn r = valid(entityTest);
        XValidator.err(r);
        if (vo.getItems().size() != entityTest.getEtest_question_total()) {
            XReturn rr = XReturn.getR(20686, "提交题目数量异常");
            rr.setData("client_size", vo.getItems().size());
            rr.setData("sys_size", entityTest.getEtest_question_total());
            return rr;
        }
        //考试用时
        long submitMinute = XDate.between(entityResult.getEtres_submit_date(), XDate.now()).toMinutes();
        if (submitMinute > entityTest.getEtest_test_minute() + 1) {
            //return XReturn.getR(20689, "提交已超时，无法提交，" + submitMinute);
            submitMinute = entityTest.getEtest_test_minute();
        }
        //考试X分钟前，不能提交
        if (submitMinute < entityTest.getEtest_test_not_submit()) {
            return XReturn.getR(20676, "提交不能太快，" + submitMinute);
        }

        if (submitMinute >= entityTest.getEtest_test_minute()) {
            submitMinute = entityTest.getEtest_test_minute();
        }
        long submitMinuteX = submitMinute;

        return XApp.getTransaction().execute(status -> {
            //题目ID
            List<String> itemIds = vo.getItems().stream().map(item -> item.getItem_id()).collect(Collectors.toList());
            //
            String[] select = {"etri_id", "etqu_answer", "etri_question_id", "etques_fun", "etri_etques_id"};
            JoinWrapperPlus<EssTestResultItem> query = listResultItemQuery();
            query.join(EssTestQuestion.table(), EssTestQuestion.tableKey(), "etri_etques_id");
            query.join(EssQuestion.table(), EssQuestion.tableKey(), "etri_question_id");
            query.in(EssTestQuestion.tableKey(), itemIds)
                    .eq("etri_uid", entityResult.getEtres_uid());
            query.select(select);
            List<Map<String, Object>> listResultItem = EssTestResultItemService.getBean().getMaps(query);
            if (listResultItem.size() != entityTest.getEtest_question_total()) {
                return XReturn.getR(20696, "提交题目数量异常，检查ID");
            }

            Long funTotal = 0L;
            for (Map<String, Object> mapItem : listResultItem) {
                String itemId = (String) mapItem.get("etri_id");
                String answer = (String) mapItem.get("etqu_answer"); //正确答案
                Long fun = (Long) mapItem.get("etques_fun"); //单题得分
                String questionId = (String) mapItem.get("etri_question_id");
                String testQuestionId = (String) mapItem.get("etri_etques_id");

                VoEssTestAnswerItem studentAnswer = vo.getItems().stream().filter(item -> item.getItem_id().equals(testQuestionId)).findFirst().orElse(null);
                String studentAnswerJson = "";
                if (studentAnswer != null
                        && studentAnswer.getAnswer() != null
                        && !studentAnswer.getAnswer().isEmpty()) {
                    Collections.sort(studentAnswer.getAnswer()); //从小到大排序
                    studentAnswerJson = XJson.toJSONString(studentAnswer.getAnswer());
                }

                Integer answerState = answer.equals(studentAnswerJson) ? 1 : 2; //回答结果

                EssTestResultItem entityItemUpdate = new EssTestResultItem();
                entityItemUpdate.setEtri_id(itemId);
                entityItemUpdate.setEtri_answer(studentAnswerJson);
                entityItemUpdate.setEtri_answer_state(answerState);
                if (answerState == 1) { //答对了
                    entityItemUpdate.setEtri_test_fun(fun);
                    funTotal += fun;
                }
                EssTestResultItemService.getBean().updateById(entityItemUpdate);
                //更新总答题数量
                int addAnswerBingo = answerState == 1 ? 1 : 0;
                {
                    SvcEssQuestion.getBean().updateAnswerTotal(questionId, 1, addAnswerBingo);
                }
                //更新测试题目答对数量
                {
                    updateTestQuestionTotal(testQuestionId, addAnswerBingo);
                }
            }

            updateAnswerEnd(entityResult, funTotal, (int) submitMinuteX);

            if (entityTest.getEtest_score_show() == 1) { //提交答案后，公布成绩
                sendFun(entityTest, entityResult.getKey());
            }

            //更新已提交人数
            getApp().update()
                    .setSql("etest_submit_total = etest_submit_total + 1")
                    .setSql("etest_submit_fun_total = etest_submit_fun_total + " + funTotal)
                    .eq("etest_id", entityTest.getKey())
                    .update();

            XReturn rr = EnumSys.OK.getR();
            rr.setData("date_end_left_minute", entityTest.dateEndLeftMinute());
            rr.setData("fun", funTotal);
            return rr;
        });
    }

    /**
     * 更新答对人数
     *
     * @param testQuestionId
     * @param addAnswerBingo
     */
    public void updateTestQuestionTotal(String testQuestionId, Integer addAnswerBingo) {
        EssTestQuestionService.getBean().update()
                .setSql("etques_answer_bingo_total = etques_answer_bingo_total + " + addAnswerBingo)
                .eq(EssTestQuestion.tableKey(), testQuestionId)
                .update()
        ;
    }

    /**
     * 结束答题
     *
     * @param entityResult
     * @param funTotal     总得分
     * @param submitMinute 用时
     */
    public void updateAnswerEnd(EssTestResult entityResult, Long funTotal, Integer submitMinute) {
        if (entityResult.getEtres_end() == 1) {
            return; //已结束
        }

        EssTestResult entityUpdate = new EssTestResult();
        entityUpdate.setEtres_id(entityResult.getEtres_id());
        entityUpdate.setEtres_end(1); //进行中
        if (funTotal != null) {
            entityUpdate.setEtres_submit(1); //交卷
            entityUpdate.setEtres_test_fun(funTotal); //总得分
            entityUpdate.setEtres_submit_minute(submitMinute); //使用时长（分）
        }
        EssTestResultService.getBean().saveOrUpdatePassEqualField(entityResult, entityUpdate);
    }

    /**
     * 获取题目每个答题选择人数
     *
     * @param testId
     * @param classId
     */
    public List<VoEssTestQuestionAnswerTotal> getAnswerTotal(String testId, List<String> classId) {
        JoinWrapperPlus<EssTestResultItem> query = listResultItemQuery();
        query.select("etri_question_id", "etri_answer", "COUNT(*) total");
        query.in("etri_class_id", classId)
                .eq("etri_test_id", testId);
        query.groupBy("etri_question_id", "etri_answer");
        List<Map<String, Object>> list = EssTestResultItemService.getBean().getMaps(query);
        List<VoEssTestQuestionAnswerTotal> listData = new ArrayList<>();
        for (Map<String, Object> item : list) {
            String questionId = (String) item.get("etri_question_id");
            String answer = (String) item.get("etri_answer");
            Long total = (Long) item.get("total");

            VoEssTestQuestionAnswerTotal itemTotal = VoEssTestQuestionAnswerTotal.of(questionId);
            itemTotal.addItem(answer, total.intValue());

            listData.add(itemTotal);
        }

        return listData;
    }
}
